package pl.us.ij.plugins.segmentation.commands.edges;

import ij.IJ;
import ij.ImagePlus;
import ij.process.ByteProcessor;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import pl.us.ij.plugins.segmentation.Trace;
import pl.us.ij.plugins.segmentation.infrastructure.Command;
import pl.us.ij.plugins.segmentation.infrastructure.exceptions.BreakCommandException;

import static pl.us.ij.plugins.segmentation.commands.threshold.GradientThresholdCommand.findThreshold;
import static pl.us.ij.plugins.segmentation.commands.threshold.OneLevelThresholdCommand.thresholdPixels;

/**
 * Created by IntelliJ IDEA.
 * User: Przemek
 * Date: 2010-01-10
 * Time: 19:48:35
 * To change this template use File | Settings | File Templates.
 */
public class SkeletonCommand extends Command<SkeletonCommandParams> {

    private ImagePlus outImp;

    @Override
    protected void processImage(FloatProcessor fp) throws BreakCommandException {
        int width = fp.getWidth();
        int height = fp.getHeight();

        SkeletonCommandParams params = getParams();

        ImageProcessor ip = fp;

        float[] pixels = (float[]) ip.getPixels();
        byte[] bytePixels = new byte[pixels.length];

        int threshold = findThreshold(width, height,pixels);

        thresholdPixels(threshold, pixels,  0, 255);



        Trace.logPixels("Negative:", pixels, 5, 5, width );

        int zeroCount = 0;

        for ( int i = 0; i < params.getIterationCount() || params.isAuto(); i++ ) {

            float[] flatMask1 = {2, 255, 2,
                    2, 0, 2,
                    0, 0, 0};
            overlapMask(width, height, pixels.clone(), pixels, flatMask1, 255);

            float[] flatMask2 = {0, 2, 2,
                    0, 0, 255,
                    0, 2, 2};
            overlapMask(width, height, pixels.clone(), pixels, flatMask2, 255);

            float[] flatMask3 = {0, 0, 0,
                    2, 0, 2,
                    2, 255, 2};
            overlapMask(width, height, pixels.clone(), pixels, flatMask3, 255);

            float[] flatMask4 = {2, 2, 0,
                    255, 0, 0,
                    2, 2, 0};
            overlapMask(width, height, pixels.clone(), pixels, flatMask4, 255);

            if ( params.isAuto() ) {
                int currentZeroCount = countPixels( pixels );
                if ( currentZeroCount == zeroCount )
                    break;
                zeroCount = currentZeroCount;
            }

            if ( IJ.escapePressed() )
                break;
        }

        Trace.logPixels("Overlapped:", bytePixels, 5, 5, width );


        for ( int i = 0; i < bytePixels.length; i++ ) {
            bytePixels[i] = (byte)pixels[i];
        }

        outImp.getProcessor().setPixels(bytePixels);
    }

    private int countPixels(float[] pixels) {
        int zeroCount = 0;
        for ( int i = 0; i < pixels.length; i++ ) {
            if ( pixels[ i] == 0 ) {
                zeroCount++;
            }
        }

        return zeroCount;
    }

    public static void negative(byte[] pixels) {
        for (int i = 0; i < pixels.length; i++) {
            pixels[i] = (byte) (255 - pixels[i]);
        }
    }

    public static void negative(float[] pixels) {
        for (int i = 0; i < pixels.length; i++) {
            pixels[i] = 255 - pixels[i];
        }
    }
    public static void overlapMask(int width, int height, float[] pixels, float[] outPixels, float[] flatMask, float color) {

        for (int y = 1; y < height - 1; y++) {
            int shift0 = width * (y - 1);
            int shift1 = width * (y);
            int shift2 = width * (y + 1);

            int shiftD = width * y;

            for (int x = 1; x < width - 1; x++) {
                boolean noChange =
                        ((flatMask[0] != 2) && (pixels[shift0 + (x - 1)] != flatMask[0])) ||  //2
                        ((flatMask[1] != 2) && (pixels[shift0 + (x)] != flatMask[1])) ||
                        ((flatMask[2] != 2) && (pixels[shift0 + (x + 1)] != flatMask[2])) ||
                        ((flatMask[3] != 2) && (pixels[shift1 + (x - 1)] != flatMask[3])) ||  //2
                        ((flatMask[4] != 2) && (pixels[shift1 + (x)] != flatMask[4])) ||
                        ((flatMask[5] != 2) && (pixels[shift1 + (x + 1)] != flatMask[5])) ||
                        ((flatMask[6] != 2) && (pixels[shift2 + (x - 1)] != flatMask[6])) ||  //2
                        ((flatMask[7] != 2) && (pixels[shift2 + (x)] != flatMask[7])) ||
                        ((flatMask[8] != 2) && (pixels[shift2 + (x + 1)] != flatMask[8]));

                if (!noChange) {
                    outPixels[shiftD + x] = color;
                }
            }
        }
    }

        @Override
    protected ImagePlus prepareOutImage(ImagePlus inImage) {

        outImp = new ImagePlus(createOutImageTitle(inImage),
                    new ByteProcessor(inImage.getWidth(), inImage.getHeight()));

        return super.prepareOutImage(inImage);
    }

    @Override
    protected boolean finalizeOutImage(ImagePlus outImp) {

        this.outImp.updateAndDraw();
        this.outImp.show(createOutImageTitle(outImp));

        return false;
    }
}
